package cn.guetzjb.sys.controller;

import cn.guet.log.anotation.Log;
import cn.guet.log.enums.BusinessType;
import cn.guet.log.enums.OperatorType;
import cn.guetzjb.core.constant.CacheConstants;
import cn.guetzjb.core.constant.SecurityConstants;
import cn.guetzjb.core.entity.R;
import cn.guetzjb.core.utils.JwtUtils;
import cn.guetzjb.redis.service.RedisService;
import cn.guetzjb.security.anotation.RequiresPermissions;
import cn.guetzjb.security.anotation.RequiresRoles;
import cn.guetzjb.security.service.TokenService;
import cn.guetzjb.security.utils.SecurityUtils;
import cn.guetzjb.sys.domain.SysUserOnline;
import cn.guetzjb.sys.model.LoginUser;
import cn.guetzjb.sys.service.SysUserOnlineService;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/online")
@Tag(name = "在线用户")
@RequiredArgsConstructor
public class UserOnlineController {

    private final RedisService redisService;
    private final SysUserOnlineService userOnlineService;

    @Value("${keys.locationKey}")
    private String locationKey; //https://lbs.qq.com/service/webService/webServiceGuide/webServiceIp 腾讯定位服务Key
    static OkHttpClient client = new OkHttpClient();

    @GetMapping("/all")
    @Operation(summary = "查询全部")
    @RequiresPermissions(value = "online:query")
    public R all(@RequestParam(required = false, defaultValue = "") String userName) {
        Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
        List<SysUserOnline> list = new ArrayList<>();
        for (String key : keys) {
            LoginUser user = redisService.getCacheObject(key);
            SysUserOnline sysUserOnline = getSysUserOnline(user);
            //记录
            long count = userOnlineService.count(Wrappers.<SysUserOnline>lambdaQuery().and(
                    v -> v.eq(SysUserOnline::getIpAddr, user.getIpaddr()).eq(SysUserOnline::getLoginName, user.getUsername())
            ));
            if (count == 0) {
                userOnlineService.save(sysUserOnline);
            }
            list.add(sysUserOnline);
        }
        List<SysUserOnline> res = list.stream().filter(v -> v.getLoginName().contains(userName))
                .sorted((o1, o2) -> (int) (o2.getLoginTime().getTime() - o1.getLoginTime().getTime())).toList();
        return R.ok(res);
    }

    private SysUserOnline getSysUserOnline(LoginUser user) {
        SysUserOnline sysUserOnline = new SysUserOnline();
        sysUserOnline.setLoginName(user.getUsername());
        sysUserOnline.setIpAddr(user.getIpaddr());
        sysUserOnline.setTokenId(user.getUserKey());
        sysUserOnline.setUserId(user.getUserId());
        sysUserOnline.setCreateTime(new Date());
        SysUserOnline online = userOnlineService.getOne(Wrappers.<SysUserOnline>lambdaQuery().and(
                v -> v.eq(SysUserOnline::getIpAddr, user.getIpaddr()).eq(SysUserOnline::getLoginName, user.getUsername())
        ));
        //获取IP地址对应的城市
        if (online != null) {
            sysUserOnline.setIpLocation(online.getIpLocation());
        } else {
            if (StringUtils.isNotEmpty(locationKey)) {
                Request request = new Request.Builder()
                        .url(String.format("https://apis.map.qq.com/ws/location/v1/ip?ip=%s&key=%s", user.getIpaddr(), locationKey))
                        .build();
                try (Response response = client.newCall(request).execute()) {
                    String string = response.body().string();
                    JSONObject jsonObject = JSONObject.parseObject(string);
                    Integer code = jsonObject.getInteger("status");
                    if (code.equals(0)) {
                        //正常调用
                        JSONObject result = jsonObject.getJSONObject("result");
                        JSONObject adInfo = result.getJSONObject("ad_info");
                        sysUserOnline.setIpLocation(adInfo.getString("province") + "-" + adInfo.getString("city") + "-" + adInfo.get("adcode"));
                    } else if (code.equals(375)) {
                        //局域网
                        sysUserOnline.setIpLocation(jsonObject.getString("message"));
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        if (user.getSysUser().getDept() != null) {
            sysUserOnline.setDeptName(user.getSysUser().getDept().getDeptName());
        }
        if (user.getSysUser().getLoginDate() != null) {
            sysUserOnline.setLoginTime(user.getSysUser().getLoginDate());
        }
        return sysUserOnline;
    }

    @PostMapping("/kick/{userId}")
    @Operation(summary = "强制下线")
    @RequiresRoles(value = {"admin"})
    @Log(title = "强制下线", businessType = BusinessType.FORCE, operatorType = OperatorType.MANAGE)
    public R kick(@PathVariable Long userId) {
        redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + userId);
        return R.ok();
    }
}
